from datetime import datetime

from rest_framework import viewsets
from django.db import transaction

from lab.common.customize_serializer import SuppressWarningSerializer
from lab.common.response import OK, Created, Deleted, NotFound


class BaseModelViewSet(viewsets.ModelViewSet):

    serializer_class = SuppressWarningSerializer
    read_serializer_class = SuppressWarningSerializer
    write_serializer_class = SuppressWarningSerializer

    def get_serializer_class(self):
        if self.action in ('create', 'update') and self.write_serializer_class != SuppressWarningSerializer :
            return self.write_serializer_class
        elif self.action in ('retrieve', 'list') and self.read_serializer_class != SuppressWarningSerializer:
            return self.read_serializer_class
        else:
            return super().get_serializer_class()

    @transaction.atomic()
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Created(data=serializer.data)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page_query = self.request.query_params.get('page')
        page = self.paginate_queryset(queryset)
        if page is not None and len(page) > 0 and page_query:
            serializer = self.get_serializer(page, many=True)
            response = self.get_paginated_response(serializer.data)
            data = response.data
        else:
            data = self.get_serializer(queryset, many=True).data

        return OK(data=data)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return OK(data=serializer.data)

    @transaction.atomic()
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', True)
        instance = self.get_object()
        self._perform_updated_user_and_time(instance)
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return OK(data=serializer.data)

    def _perform_updated_user_and_time(self, instance):
        if hasattr(instance, 'updated_time'):
            instance.updated_time = datetime.now()
        if hasattr(instance, 'updated_by'):
            instance.updated_by = self.request.user

    @transaction.atomic()
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Deleted(data={})

    @staticmethod
    def _get_object_or_404(queryset):
        if queryset:
            return queryset.first()
        else:
            raise NotFound()
